package com.yuma.tingshu.user.listener;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.rabbitmq.client.Channel;
import com.yuma.tingshu.album.client.TrackInfoFeignClient;
import com.yuma.tingshu.common.constant.RabbitConstant;
import com.yuma.tingshu.common.constant.RedisConstant;
import com.yuma.tingshu.common.constant.SystemConstant;
import com.yuma.tingshu.common.result.Result;
import com.yuma.tingshu.model.album.TrackInfo;
import com.yuma.tingshu.model.user.*;
import com.yuma.tingshu.user.mapper.*;
import com.yuma.tingshu.vo.album.TrackStatMqVo;
import com.yuma.tingshu.vo.user.UserPaidRecordVo;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.LocalDateTime;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
public class UserListener {

    @Autowired
    private UserPaidAlbumMapper paidAlbumMapper;
    @Autowired
    private UserPaidTrackMapper paidTrackMapper;
    @Autowired
    private UserInfoMapper userInfoMapper;
    @Autowired
    private UserVipServiceMapper userVipServiceMapper;
    @Autowired
    private VipServiceConfigMapper vipServiceConfigMapper;
    @Resource
    private TrackInfoFeignClient trackInfoFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Transactional
    @RabbitListener(bindings = @QueueBinding(
            value = @Queue(RabbitConstant.USER_PAID_QUEUE),
            exchange = @Exchange(value = RabbitConstant.ORDER_EXCHANGE, type = ExchangeTypes.TOPIC, ignoreDeclarationExceptions = "true"),
            key = RabbitConstant.USER_PAID_RK
    ))
    public void paidRecord(String JsonUserPaidRecordVo, Channel channel, Message message) throws IOException {
        // 1.判空
        if (StringUtils.isBlank(JsonUserPaidRecordVo)) {
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }
        // 2.反序列化这个消息并判空
        UserPaidRecordVo userPaidRecordVo = JSON.parseObject(JsonUserPaidRecordVo, UserPaidRecordVo.class);
        if (userPaidRecordVo == null || userPaidRecordVo.getUserId() == null || StringUtils.isBlank(userPaidRecordVo.getItemType())) {
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }
        // 3.幂等性
        String idem = RedisConstant.USER_RECORD_IDEM_PREFIX + userPaidRecordVo.getOrderNo();
        if (!redisTemplate.opsForValue().setIfAbsent(idem, "", RedisConstant.ALBUM_TIMEOUT, TimeUnit.SECONDS)) {
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        String orderNo = userPaidRecordVo.getOrderNo();
        Long userId = userPaidRecordVo.getUserId();
        // 获取明细集合:专辑订单应该有且只有一个明细
        List<Long> itemIdList = userPaidRecordVo.getItemIdList();
        if (StringUtils.isBlank(orderNo) || userId == null || StringUtils.isBlank(userPaidRecordVo.getItemType())) {
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            return;
        }

        try {
            // 4.判断订单类型
            switch (userPaidRecordVo.getItemType()) {
                // 4.1 vip处理
                case SystemConstant.ORDER_ITEM_TYPE_VIP:
                    if (itemIdList == null || itemIdList.size() != 1) {
                        channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                        return;
                    }
                    // 幂等性操作
                    // 4.1.1 根据 集合中获取第一个id值就是vip_service_config的id，查询VipServiceconfig对象
                    VipServiceConfig vipServiceConfig = this.vipServiceConfigMapper.selectById(itemIdList.get(0));
                    // 4.1.2 根据userId查询用户信息，判断是否已经是vip
                    UserInfo userInfo = this.userInfoMapper.selectById(userId);
                    if (userInfo == null || vipServiceConfig == null) {
                        channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                        return;
                    }
                    // VIP生效时间
                    Date startTime = new Date();
                    if (userInfo.getIsVip() == 1) {
                        // 如果是vip,vip服务的起始时间就是之前的过期时间
                        startTime = userInfo.getVipExpireTime();
                        // 4.1.1.1 如果已经是vip，则is_vip=1，过期时间oldExpireTime + service_month，更新 user_info
                        LocalDateTime oldExpireTime = LocalDateTime.fromDateFields(userInfo.getVipExpireTime());
                        // 如果是vip则在原来过期时间的基础上累加对应的服务月份
                        Date newExpireTime = oldExpireTime.plusMonths(vipServiceConfig.getServiceMonth()).toDate();
                        userInfo.setVipExpireTime(newExpireTime);
                    } else {
                        // 4.1.1.2 不是vip，则is_vip=0设置成1，过期时间now() + service_month，更新 user_info
                        userInfo.setIsVip(1);
                        // 不是vip则在当前时间的基础上累加对应的服务月份
                        Date expireTime = LocalDateTime.now().plusMonths(vipServiceConfig.getServiceMonth()).toDate();
                        userInfo.setVipExpireTime(expireTime);
                    }
                    // 记录vip购买行为，更新 user_info，如果是vip则过期时间加1年，如果不是则改为一年过期，更改is_vip=1
                    if (1 == userInfoMapper.updateById(userInfo)) {
                        // 4.1.1.3 添加一条到user_vip_service表
                        UserVipService userVipService = userVipServiceMapper.selectOne(new LambdaQueryWrapper<UserVipService>()
                                .eq(UserVipService::getOrderNo, orderNo));
                        // 购买过就确认掉
                        if (userVipService != null) {
                            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                            return;
                        }
                        // 记录vip购买明细
                        userVipService = new UserVipService();
                        userVipService.setOrderNo(orderNo);
                        userVipService.setUserId(userId);
                        userVipService.setStartTime(startTime);  // 生效时间
                        userVipService.setExpireTime(userInfo.getVipExpireTime());
                        this.userVipServiceMapper.insert(userVipService);
                        // 应答
                        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                    } else {
                        channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                    }
                    break;
                // 4.2 album处理:
                case SystemConstant.ORDER_ITEM_TYPE_ALBUM:
                    //4.2.1 直接添加一条 user_paid_album中
                    if (itemIdList == null || itemIdList.size() != 1) {
                        channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                        return;
                    }
                    // 保证幂等性，一个订单只能记录一次
                    UserPaidAlbum userPaidAlbum = this.paidAlbumMapper.selectOne(new LambdaQueryWrapper<UserPaidAlbum>()
                            .eq(UserPaidAlbum::getOrderNo, orderNo));
                    if (userPaidAlbum != null) {
                        // 已经记录过，确认掉
                        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                        return;
                    }
                    // 没有记录过进行记录
                    userPaidAlbum = new UserPaidAlbum();
                    userPaidAlbum.setOrderNo(orderNo);
                    userPaidAlbum.setUserId(userId);
                    userPaidAlbum.setAlbumId(itemIdList.get(0));
                    if (1 == paidAlbumMapper.insert(userPaidAlbum)) {
                        //4.2.2 发送消息给jsonTrackStatMqVo 发送给AlbumListener，专辑购买量0403+1
                        TrackStatMqVo trackStatMqVo = new TrackStatMqVo();
                        trackStatMqVo.setBusinessNo(userPaidRecordVo.getOrderNo());
                        trackStatMqVo.setAlbumId(itemIdList.get(0));
                        trackStatMqVo.setStatType(SystemConstant.ALBUM_STAT_BROWSE);
                        trackStatMqVo.setCount(1);
                        // TODO: 发送消息给专辑MQ，记录专辑的购买次数
                        rabbitTemplate.convertAndSend(RabbitConstant.ALBUM_EXCHANGE, RabbitConstant.PLAY_STAT_RK, JSON.toJSONString(trackStatMqVo));
                        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                    } else {
                        channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                    }
                    break;
                // 4.3 track处理:
                case SystemConstant.ORDER_ITEM_TYPE_TRACK:  // 声音订单
                    if (CollectionUtils.isEmpty(itemIdList)) {
                        channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
                        return;
                    }
                    // 一个订单只能记录一次，保证幂等性
                    if (paidTrackMapper.selectCount(new LambdaQueryWrapper<UserPaidTrack>()
                            .eq(UserPaidTrack::getOrderNo, orderNo)) != 0) {
                        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                        return;
                    }
                    // 根据第一个声音的id查询声音
                    Result<TrackInfo> trackInfoResult = trackInfoFeignClient.getTrackInfo(itemIdList.get(0));
                    Assert.notNull(trackInfoResult, "记录声音的购买明细时，获取声音信息失败");
                    TrackInfo trackInfo = trackInfoResult.getData();
                    Assert.notNull(trackInfo, "记录声音的购买明细时，获取声音信息失败");

                    //4.3.1 直接添加一条user_paid_track中
                    // 如果没记录可以记录，遍历声音id，每一个声音记录一次
                    itemIdList.forEach(trackId -> {
                        UserPaidTrack userPaidTrack = new UserPaidTrack();
                        userPaidTrack.setOrderNo(orderNo);
                        userPaidTrack.setUserId(userId);
                        userPaidTrack.setAlbumId(trackInfo.getAlbumId());
                        userPaidTrack.setTrackId(trackId);
                        this.paidTrackMapper.insert(userPaidTrack);
                    });
                    channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                    break;
            }
        } catch (Exception e) {
            // 数据库操作异常
            if (!message.getMessageProperties().getRedelivered()) {
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
            } else {
                channel.basicReject(message.getMessageProperties().getDeliveryTag(), false);
            }
        }
    }
}